package com.cy.pj.common.aspect;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SysCacheAspect {
     //假设这个容器就是cache (当然这个cache将来还需要进行更好的设计)
	 private Map<Object,Object> cache=new ConcurrentHashMap<>();//线程安全的hashMap
	 /**基于@annotation(注解类全名)表达式定义切入点(这种切入点通常理解为细粒度的切入点)*/
	 @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredCache)")
	 public void doCache() {}
	 
	 @Pointcut("@annotation(com.cy.pj.common.annotation.ClearCache)")//这个注解自己定义
	 public void doClearCache() {}
	 //FAQ?我现在需要一个清除cache的通知方法,我们该写在哪个通知方法中?
	 
	 @AfterReturning("doClearCache()")
	 public void doAfterReturning(JoinPoint jp) {
		 cache.clear();
		 //cache.remove(key);
	 }
	 
	 @Around("doCache()")
	 public Object around(ProceedingJoinPoint jp)throws Throwable{
		 //1.从cache获取数据,假如cache中有我们需要的数据则直接返回,不需要再查数据,这样可以确保更好的性能.
		 System.out.println("Get data from cache");
		 Object result=cache.get("dept");//这个key名字现在是自己随意指定的(将来可以写的更灵活)
		 //FAQ?如何将cache中的key定义的更加灵活(在描述切入点的方法注解中直接指定key)
		 //FAQ?如何获取切入点方法上的注解中的key?(首先获取目标方法,然后基于目标方法获取方法上注解,再通过注解取key的值)
		 if(result!=null)return result;
		 //2.假如cache中没有,则从数据库去查询.
		 result=jp.proceed();//目标方法
		 System.out.println("Put data to cache");
		 //3.将查询的结果存储到cache,便于下次查询使用.
		 cache.put("dept", result);
		 return result;
	 }
}
